/**

=blacksmith/doc - Documentation generator

The doc module generates documentation from blacksmith modules.

*/



window.DOC = {}


DOC.re_commentblocks = /\/\*\*[\s\S]*?\*\//gm,

DOC.re_trimline      = /^\s*\**\s*/,

DOC.re_whitespace    = /\s/gm,

DOC.re_anchorrem     = /[ "'\[\]\)?{}]/g,

DOC.re_anchorrep     = /[,\(]/g




DOC.generate = function(filepath) {
    /**
     *> DOC.generate('filepath')
     * 
     * Renders documentation parsed from the specified filepath
     * 
     */
    
    if (/\/$/.test(filepath))
        filepath += '__dir__.js'
    
    var ancestors = OS.PATH.abspath(filepath).split('/'),
        module = ancestors.pop()
    
    // Default module is __dir__.js
    if (module === '' || module === null)
        module = '__dir__.js'
    
    document.body.innerHTML += [
        '<table id="DOC-frame" width="100%" border="0" cellpadding="0" cellspacing="0">',
        '<tbody>',
        '<tr>',
        '<td id="breadcrumb" colspan="2">',
        '</td>',
        '</tr>',
        '<tr>',
        '<td id="DOC-toc" valign="top">',
        '</td>',
        '<td id="DOC-body" valign="top">',
        '</td>',
        '</tr>',
        '</tbody>',
        '</table>'
    ].join('')
    
    DOC.breadcrumb(ancestors, module)
    
    DOC.toc(ancestors, module)
    
    DOC.body(filepath)
    
}






DOC.body = function(filepath) {
    
    var html = '',
        blocks,
        block,
        comments,
        comment,
        anchor,
        code = false,
        blacksmithrun = null,
        indent = false,
        tokens,
        token,
        param
    
    FILE.File(filepath).read(function (result) {
        
        if (BLACKSMITH.isError(result))
            return print(result)
        
        blocks = result.file.content.match(DOC.re_commentblocks)
        
        if (blocks === null)
            return
        
        /**
         *=Documentation rules
         * 
         * blacksmith/doc will find documentation from comment blocks and render according to the following rules.
         * 
         */
        for (block in blocks) {
            
            block = blocks[block]
            comments = block.split('\n')
            
            for (comment in comments) {
                comment = comments[comment]
                comment = comment.replace(DOC.re_trimline, '')
                
                /**
                 *./**
                 *. *
                 *. *@blacksmithrun global.callback declaration will cause blacksmith/doc to call 'global.callback()' after rendering
                 *. *
                 */
                print('['+comment+']'+(comment == '/**'))
                if (comment[0] === '=') {
                    /**
                     *. *
                     *. *=headings start with an asterisk
                     *. *
                     */
                    
                    if (code) {html += '</pre>'; code = false}
                    if (indent) {html += '</div>'; indent = false}
                    
                    html += '<div class="heading">' + comment.replace(/\=/, '') + '</div>'
                    
                } else if (comment[0] === '>') {
                    /**
                     *. *> MODULE.function('stringparam', objectparam) start with a greater than
                     *. *
                     */
                    
                    comment = comment.replace(/^>/, '')
                    
                    anchor = comment.replace(DOC.re_anchorrem, '').replace(DOC.re_anchorrep, ',')
                    
                    if (code) {html += '</pre>'; code = false}
                    if (indent) html += '</div>'
                    
                    html += '<a id="' + anchor + '" class="anchor" name="' + anchor + '" href="#' + anchor + '">'
                    html += '<div class="function">'
                    
                    tokens = BLACKSMITH.tokenise(comment)
                    param = false
                    
                    for (token in tokens) {
                        token = tokens[token]
                        if (token.value === '(')
                            param = true
                        else if (token.type === 5) {
                            if (param)
                                token.type = 9
                            else if (!/[a-z]/.test(token.value))
                                token.type = 8
                        }
                        html += '<span class="DOC-light-' + token.type + '">' + token.value + '</span>'
                    }
                    
                    html += '</div>'
                    html += '</a><div class="DOC-indent">'
                    indent = true
                    
                } else if (comment.replace(DOC.re_whitespace, '') === '') {
                    
                    if (code) {html += '</pre>'; code = false}
                    
                } else if (comment[0] === '.') {
                    /**
                     *. *. code block lines start with a period
                     *. *
                     *. * As can be seen, the content of code blocks is syntax highlighted.
                     *. *=
                     *. * A function creates an indentation that is ended by another function or heading.
                     *. *
                     */
                    
                    if (!code) html += '<pre>'
                    
                    code = true
                    
                    tokens = BLACKSMITH.tokenise(comment.replace(/\./, ''))
                    for (token in tokens) {
                        token = tokens[token]
                        if (token.type === 5 && !/[a-z]/.test(token.value))
                            token.type = 8
                        html += '<span class="DOC-dark-' + token.type + '">' + token.value + '</span>'
                    }
                    
                    html += '\n'
                    
                } else if (comment === '/*'+'*') {
                    
                } else if (comment === '/') {
                    
                    if (!code) html += '<br/><br/>'
                    
                } else if (comment[0] === '@') {
                    
                    if (/@blacksmithrun /.test(comment))
                        blacksmithrun = comment.replace('@blacksmithrun ', '').replace(/\s/, '')
                    
                } else {
                    print('here')
                    
                    if (code) {html += '</pre>'; code = false}
                    
                    html += comment + ' '
                    
                }
            }
        }
        
        document.getElementById('DOC-body').innerHTML = html
        
        if (blacksmithrun != null) {
            
            if (BLACKSMITH.main === 'blacksmith/doc')
                eval(result.file.content)
            
            eval(blacksmithrun)
            
        }
        
    })
    
    DOC.fillToBottom()
    window.onresize = DOC.fillToBottom
    
}





DOC.breadcrumb = function(ancestors, module) {
    
    var crumb = '<a href="/blacksmith/doc?f=/">home</a>',
        path = '/',
        i
    
    for (i in ancestors) {
        
        if (ancestors[i] === '')
            continue
        
        path += ancestors[i] + '/'
        
        crumb += ' \u00B7 <a href="/blacksmith/doc?f=' + path + '">' + ancestors[i] + '</a>'
        
    }
    
    if (module !== '__dir__.js') {
        crumb += '\u00B7 <a href="/blacksmith/doc?f=' + path + module + '">' + module.replace(/(\.js|\/)$/, '') + '</a>'
    }
    
    crumb += '<span class="DOC-tools"><a href="/blacksmith/term?p=' + path + '" target="_blank">#</a><a href="/blacksmith/ji?f=' + path + module + '" target="_blank">&#x270e;</a></span>'
    
    document.getElementById('breadcrumb').innerHTML = crumb
    
}





DOC.toc = function(ancestors, module) {
    
    var path = ancestors.join('/') + '/',
        html = '',
        files,
        file,
        label
    
    OS.read(path, function (result) {
        
        if (BLACKSMITH.isError(result))
            return
        
        files = JSON.parse(result)
        i = files.length
        
        while (files.length) {
            
            file = files.pop()
            
            if (file === '__dir__.js')
                continue
            
            label = file.replace(/(\.js)$/, '')
            html += '<div class="' + (/\/$/.test(file) ? 'directory' : /\.js$/.test(file) ? 'filejs' : 'file') + '">'
            
            if (label !== module)
                html += '<a href="/blacksmith/doc?f=' + path + file + '">'
            
            html += label
            
            if (label !== module)
                html += '</a>'
            
            html += '</div>'
            
        }
        
        document.getElementById('DOC-toc').innerHTML = html
        
    })
    
}



DOC.fillToBottom = function() {
    
    var frame = document.getElementById('DOC-frame'),
        body = document.getElementById('DOC-body'),
        available = window.innerHeight || document.documentElement.clientHeight
    
    if (frame.offsetHeight < available)
        body.style.height = body.offsetHeight + (available - frame.offsetHeight) - 30 + 'px'
    
}


if (BLACKSMITH.__main__ === 'blacksmith/doc') {
    /**
     *=Main application
     *
     * When run as the main application this module will call
     * DOC.generate(f), where f is passed as an argument on the URL.
     *
     *. URL:     /blacksmith/doc?f=/blacksmith/doc.js
     *. blacksmith/term: blacksmith/doc blacksmith/doc.js
     *
     */
    
    var filepath = 'blacksmith/doc.js',
        anchor = ''
    
    BLACKSMITH.args.forEach(function (arg) {
        if (arg[0] === 'f') {
            filepath = arg[1].replace(/#.*$/, '')
            anchor = arg[1].replace(/^.*#/, '')
        }
        if (!/\/$/.test(filepath) && !/\.[^\/]*$/.test(filepath))
            filepath += '.js'
    })
    
    document.title += ' : ' + OS.PATH.abspath(filepath)
    DOC.generate(filepath)
    
    if (anchor.length > 0) {
        anchor = document.getElementById(anchor)
        if (anchor !== null)
            anchor.scrollIntoView()
    }
}




BLACKSMITH.element(document.head, 'style', {'type': 'text/css'}, [
    'body {',
    '  font-family: Tahoma,Helvetica,"Helvetica Neue",Arial,sans-serif;',
    '  font-size: 100%;',
    '  margin: 0;',
    '  color: #555555;',
    '  background: #aaaaaa;',
    '}',
    
    'a {',
    '  color: #5498c3;',
    '}',
    
    'a:link    {text-decoration: none;}',
    'a:visited {text-decoration: none;}',
    'a:active  {text-decoration: none;}',
    'a:hover   {text-decoration: underline;}',
    '.header {',
    '  background: #333333;',
    '  border-bottom: 1px solid black;',
    '  height: 20px;',
    '  padding: 5px;',
    '  color: #F58F31;',
    '}',
    
    '#breadcrumb {',
    '  color: #000000;',
    '  padding: 10px;',
    '}',
    
    '#breadcrumb a {',
    '  color: #ffffff;',
    '}',
    
    '#DOC-toc {',
    '  width: 150px;',
    '  padding: 10px;',
    '  padding-right: 20px;',
    '  padding-top: 50px;',
    '}',
    
    '#DOC-body {',
    '  width: 100%;',
    '  padding-top: 20px;',
    '  padding-left: 20px;',
    '  padding-right: 50px;',
    '  padding-bottom: 10px;',
    '  background: #ffffff;',
    '  -moz-border-top-left-radius: 10px;',
    '  border-top-left-radius: 10px;',
    '  border-top: 2px solid #888888;',
    '  border-left: 2px solid #888888;',
    '}',
    
    '.heading:first-child {',
    '  margin-top: 0;',
    '  font-size: 250%;',
    '  color: #FB5F22;',
    '}',
    
    '.heading {',
    '  margin-top: 40px;',
    '  margin-bottom: 10px;',
    '  font-size: 150%;',
    '  color: #FB5F22;',
    '}',
    
    '.description {',
    '  padding-left: 20px;',
    '}',
    
    'pre {',
    '  background: #333333;',
    '  color: #ffffff;',
    '  border-top: 1px solid #FB5F22;',
    '  border-bottom: 1px solid #FB5F22;',
    '  padding-top: 10px;',
    '  padding-bottom: 10px;',
    '}',
    
    '.DOC-tools {',
    '  float: right;',
    '}',
    
    '.DOC-tools a {',
    '  margin-left: 20px;',
    '}',
    
    '.anchor {',
    '  color: #F58F31;',
    '}',
    
    '.function {',
    '  color: black;',
    '  padding-top: 10px;',
    '  padding-bottom: 10px;',
    '  font-weight: bold;',
    '}',
    
    '#DOC-toc .directory a {',
    '  color: #ffffff;',
    '}',
    
    '#DOC-toc .filejs a {',
    '  color: #ffffff;',
    '}',
    
    '#DOC-toc .file a {',
    '  color: #cccccc;',
    '}',
    
    '.DOC-indent {',
    '  padding-left: 20px;',
    '}',
    
    '.DOC-light-0 {color:#777777}',//operator
    '.DOC-light-1 {color:#bbbbbb}',//space
    '.DOC-light-2 {color:#bbbbbb}',//linebreak
    '.DOC-light-3 {color:#929204}',//comment
    '.DOC-light-4 {color:#ff0000}',//reserved word
    '.DOC-light-5 {color:#000000}',//name
    '.DOC-light-6 {color:#2020b9}',//number
    '.DOC-light-7 {color:#256a31}',//string
    '.DOC-light-8 {color:#777777}',//module
    '.DOC-light-9 {color:#000000;font-style:italic}',//parameter
    
    '.DOC-dark-0 {color:#C19859}',//operator
    '.DOC-dark-1 {color:#333333}',//space
    '.DOC-dark-2 {color:#3a3a3a}',//linebreak
    '.DOC-dark-3 {color:#f2f264}',//comment
    '.DOC-dark-4 {color:#e06c1f}',//reserved word
    '.DOC-dark-5 {color:#FFFFFF}',//name
    '.DOC-dark-6 {color:#0086FF}',//number
    '.DOC-dark-7 {color:#7D8349}',//string
    '.DOC-dark-8 {color:#C19859}'//module
    
])

